<!-- 脉冲密度热力图 - 百万脉冲/秒可视化 -->
<template>
  <div class="pulse-density-heatmap">
    <!-- 热力图控制栏 -->
    <div class="heatmap-controls">
      <div class="controls-left">
        <h3 class="heatmap-title">
          <el-icon><TrendCharts /></el-icon>
          脉冲密度热力图
        </h3>
        <div class="density-stats">
          <el-tag size="small" type="success">{{ currentDensity }}M脉冲/秒</el-tag>
          <el-tag size="small" type="warning">峰值: {{ peakDensity }}M脉冲/秒</el-tag>
          <el-tag size="small" type="info">平均: {{ avgDensity }}M脉冲/秒</el-tag>
        </div>
      </div>

      <div class="controls-right">
        <el-button-group size="small">
          <el-button @click="toggleRealtime" :type="isRealtime ? 'success' : 'default'">
            <el-icon><VideoPlay v-if="!isRealtime" /><VideoPause v-else /></el-icon>
            {{ isRealtime ? '实时' : '暂停' }}
          </el-button>
          <el-button @click="exportData">
            <el-icon><Download /></el-icon>
            导出
          </el-button>
          <el-button @click="resetView">
            <el-icon><RefreshRight /></el-icon>
            重置
          </el-button>
        </el-button-group>
      </div>
    </div>

    <!-- 主热力图容器 -->
    <div class="heatmap-container" ref="heatmapContainer">
      <div class="heatmap-wrapper">
        <!-- 频率轴标签 -->
        <div class="frequency-axis">
          <div class="axis-title">频率 (GHz)</div>
          <div class="frequency-labels">
            <div v-for="freq in frequencyTicks" :key="freq" class="freq-label">
              {{ freq }}
            </div>
          </div>
        </div>

        <!-- 热力图画布 -->
        <div class="heatmap-canvas-container">
          <canvas ref="heatmapCanvas" class="heatmap-canvas"></canvas>

          <!-- 密度数值显示覆盖层 -->
          <div class="density-overlay" v-show="showDensityValues">
            <div
              v-for="(cell, index) in visibleDensityCells"
              :key="index"
              class="density-cell"
              :style="cell.style"
            >
              {{ cell.value }}
            </div>
          </div>
        </div>

        <!-- 时间轴 -->
        <div class="time-axis">
          <div class="axis-title">时间</div>
          <div class="time-labels">
            <div v-for="time in timeTicks" :key="time" class="time-label">
              {{ time }}
            </div>
          </div>
        </div>
      </div>

      <!-- 色彩条 -->
      <div class="colorbar">
        <div class="colorbar-title">脉冲密度 (M/s)</div>
        <div class="colorbar-gradient" ref="colorbarGradient"></div>
        <div class="colorbar-scale">
          <span v-for="tick in colorbarTicks" :key="tick" class="colorbar-tick">
            {{ tick }}
          </span>
        </div>
      </div>
    </div>

    <!-- 参数控制面板 -->
    <div class="control-panels">
      <!-- 显示控制 -->
      <div class="control-panel">
        <h4 class="panel-title">显示控制</h4>
        <div class="control-group">
          <div class="control-item">
            <label>时间窗口</label>
            <el-select v-model="timeWindow" @change="onTimeWindowChange" size="small">
              <el-option label="1秒" value="1s"></el-option>
              <el-option label="5秒" value="5s"></el-option>
              <el-option label="10秒" value="10s"></el-option>
              <el-option label="30秒" value="30s"></el-option>
            </el-select>
          </div>

          <div class="control-item">
            <label>频率范围</label>
            <el-select v-model="frequencyRange" @change="onFreqRangeChange" size="small">
              <el-option label="1-6 GHz" value="1-6"></el-option>
              <el-option label="6-18 GHz" value="6-18"></el-option>
              <el-option label="18-40 GHz" value="18-40"></el-option>
              <el-option label="全频段" value="full"></el-option>
            </el-select>
          </div>

          <div class="control-item">
            <el-checkbox v-model="showDensityValues">显示数值</el-checkbox>
          </div>

          <div class="control-item">
            <el-checkbox v-model="showGrid">显示网格</el-checkbox>
          </div>
        </div>
      </div>

      <!-- 阈值控制 -->
      <div class="control-panel">
        <h4 class="panel-title">阈值设置</h4>
        <div class="threshold-controls">
          <div class="threshold-item">
            <label>最小显示密度</label>
            <el-slider
              v-model="minThreshold"
              :min="0"
              :max="10"
              :step="0.1"
              @change="onThresholdChange"
              class="threshold-slider"
            />
            <span class="threshold-value">{{ minThreshold }}M/s</span>
          </div>

          <div class="threshold-item">
            <label>最大显示密度</label>
            <el-slider
              v-model="maxThreshold"
              :min="10"
              :max="1000"
              :step="1"
              @change="onThresholdChange"
              class="threshold-slider"
            />
            <span class="threshold-value">{{ maxThreshold }}M/s</span>
          </div>

          <div class="threshold-item">
            <label>更新频率</label>
            <el-slider
              v-model="updateRate"
              :min="1"
              :max="60"
              @change="onUpdateRateChange"
              class="threshold-slider"
            />
            <span class="threshold-value">{{ updateRate }}Hz</span>
          </div>
        </div>
      </div>

      <!-- 统计信息 -->
      <div class="control-panel">
        <h4 class="panel-title">统计信息</h4>
        <div class="stats-grid">
          <div class="stat-item">
            <label>总脉冲数</label>
            <span class="stat-value">{{ totalPulses.toLocaleString() }}</span>
          </div>
          <div class="stat-item">
            <label>活跃频点</label>
            <span class="stat-value">{{ activeFreqPoints }}</span>
          </div>
          <div class="stat-item">
            <label>峰值时刻</label>
            <span class="stat-value">{{ peakTime }}</span>
          </div>
          <div class="stat-item">
            <label>数据覆盖率</label>
            <span class="stat-value">{{ coverageRate }}%</span>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, reactive, computed, onMounted, onBeforeUnmount, nextTick } from 'vue'
import { ElMessage } from 'element-plus'
import {
  TrendCharts,
  VideoPlay,
  VideoPause,
  Download,
  RefreshRight
} from '@element-plus/icons-vue'

// 状态管理
const isRealtime = ref(true)
const showDensityValues = ref(false)
const showGrid = ref(true)

// 控制参数
const timeWindow = ref('10s')
const frequencyRange = ref('1-6')
const minThreshold = ref(1.0)
const maxThreshold = ref(100)
const updateRate = ref(5)

// 统计数据
const currentDensity = ref(45.2)
const peakDensity = ref(892.5)
const avgDensity = ref(125.8)
const totalPulses = ref(15847293)
const activeFreqPoints = ref(1247)
const peakTime = ref('14:32:15')
const coverageRate = ref(89.3)

// DOM引用
const heatmapContainer = ref(null)
const heatmapCanvas = ref(null)
const colorbarGradient = ref(null)

// 轴标签数据
const frequencyTicks = computed(() => {
  const range = frequencyRange.value
  switch (range) {
    case '1-6':
      return ['1.0', '2.0', '3.0', '4.0', '5.0', '6.0']
    case '6-18':
      return ['6', '8', '10', '12', '14', '16', '18']
    case '18-40':
      return ['18', '22', '26', '30', '34', '38', '40']
    default:
      return ['1', '5', '10', '15', '20', '25', '30', '35', '40']
  }
})

const timeTicks = computed(() => {
  const window = timeWindow.value
  const now = new Date()
  const ticks = []

  const interval = window === '1s' ? 0.2 : window === '5s' ? 1 : window === '10s' ? 2 : 6
  const count = window === '1s' ? 5 : window === '5s' ? 5 : window === '10s' ? 5 : 5

  for (let i = count; i >= 0; i--) {
    const time = new Date(now.getTime() - i * interval * 1000)
    ticks.push(time.toLocaleTimeString('zh-CN', {
      hour12: false,
      minute: '2-digit',
      second: '2-digit'
    }))
  }

  return ticks
})

const colorbarTicks = computed(() => {
  const min = minThreshold.value
  const max = maxThreshold.value
  const step = (max - min) / 4

  return [
    min.toFixed(1),
    (min + step).toFixed(1),
    (min + 2 * step).toFixed(1),
    (min + 3 * step).toFixed(1),
    max.toFixed(1)
  ]
})

// 热力图数据
const heatmapData = reactive({
  width: 100,
  height: 60,
  data: []
})

const visibleDensityCells = computed(() => {
  if (!showDensityValues.value) return []

  const cells = []
  const cellWidth = 100 / heatmapData.width
  const cellHeight = 100 / heatmapData.height

  for (let i = 0; i < heatmapData.height; i += 3) {
    for (let j = 0; j < heatmapData.width; j += 5) {
      const value = heatmapData.data[i * heatmapData.width + j] || 0
      if (value > minThreshold.value) {
        cells.push({
          value: value.toFixed(1),
          style: {
            left: `${j * cellWidth}%`,
            top: `${i * cellHeight}%`,
            width: `${cellWidth * 5}%`,
            height: `${cellHeight * 3}%`
          }
        })
      }
    }
  }

  return cells
})

// Canvas相关
let ctx = null
let animationFrame = null
let lastUpdateTime = 0

// 初始化热力图数据
const initHeatmapData = () => {
  const { width, height } = heatmapData
  heatmapData.data = new Array(width * height).fill(0)

  // 生成初始数据
  generatePulseData()
}

// 生成模拟脉冲数据
const generatePulseData = () => {
  const { width, height, data } = heatmapData

  for (let i = 0; i < height; i++) {
    for (let j = 0; j < width; j++) {
      const freqWeight = Math.exp(-Math.pow((i - height * 0.3) / (height * 0.2), 2))
      const timeWeight = Math.exp(-Math.pow((j - width * 0.7) / (width * 0.3), 2))
      const noise = Math.random() * 0.3

      const baseDensity = freqWeight * timeWeight * 100 + noise * 20
      const spikes = Math.random() < 0.02 ? Math.random() * 500 : 0

      data[i * width + j] = Math.max(0, baseDensity + spikes)
    }
  }

  updateStatistics()
}

// 更新统计信息
const updateStatistics = () => {
  const { data } = heatmapData

  currentDensity.value = data[Math.floor(Math.random() * data.length)]?.toFixed(1) || 0
  peakDensity.value = Math.max(...data).toFixed(1)
  avgDensity.value = (data.reduce((sum, val) => sum + val, 0) / data.length).toFixed(1)

  // 更新其他统计数据
  totalPulses.value += Math.floor(Math.random() * 1000)
  activeFreqPoints.value = data.filter(val => val > minThreshold.value).length
  coverageRate.value = ((activeFreqPoints.value / data.length) * 100).toFixed(1)
}

// 初始化Canvas
const initCanvas = () => {
  const canvas = heatmapCanvas.value
  if (!canvas) return

  canvas.width = canvas.offsetWidth
  canvas.height = canvas.offsetHeight

  ctx = canvas.getContext('2d')
  if (!ctx) return

  // 初始化色彩条
  initColorbar()

  // 开始渲染
  renderHeatmap()
  startUpdateLoop()
}

// 初始化色彩条
const initColorbar = () => {
  const colorbar = colorbarGradient.value
  if (!colorbar) return

  const gradient = 'linear-gradient(to top, ' +
    '#000080 0%, #0000FF 20%, #00FFFF 40%, #00FF00 60%, #FFFF00 80%, #FF0000 100%)'

  colorbar.style.background = gradient
}

// 渲染热力图
const renderHeatmap = () => {
  if (!ctx) return

  const canvas = ctx.canvas
  const { width, height, data } = heatmapData

  // 清空画布
  ctx.clearRect(0, 0, canvas.width, canvas.height)

  // 计算单元格大小
  const cellWidth = canvas.width / width
  const cellHeight = canvas.height / height

  // 绘制热力图
  for (let i = 0; i < height; i++) {
    for (let j = 0; j < width; j++) {
      const value = data[i * width + j]
      const normalizedValue = Math.min(1, Math.max(0,
        (value - minThreshold.value) / (maxThreshold.value - minThreshold.value)
      ))

      if (normalizedValue > 0) {
        ctx.fillStyle = getHeatmapColor(normalizedValue)
        ctx.fillRect(
          j * cellWidth,
          (height - 1 - i) * cellHeight,
          cellWidth,
          cellHeight
        )
      }
    }
  }

  // 绘制网格
  if (showGrid.value) {
    drawGrid()
  }
}

// 获取热力图颜色
const getHeatmapColor = (value) => {
  const colors = [
    { r: 0, g: 0, b: 128 },     // 深蓝
    { r: 0, g: 0, b: 255 },     // 蓝
    { r: 0, g: 255, b: 255 },   // 青
    { r: 0, g: 255, b: 0 },     // 绿
    { r: 255, g: 255, b: 0 },   // 黄
    { r: 255, g: 0, b: 0 }      // 红
  ]

  const scaledValue = value * (colors.length - 1)
  const index = Math.floor(scaledValue)
  const fraction = scaledValue - index

  if (index >= colors.length - 1) {
    const color = colors[colors.length - 1]
    return `rgb(${color.r}, ${color.g}, ${color.b})`
  }

  const color1 = colors[index]
  const color2 = colors[index + 1]

  const r = Math.round(color1.r + (color2.r - color1.r) * fraction)
  const g = Math.round(color1.g + (color2.g - color1.g) * fraction)
  const b = Math.round(color1.b + (color2.b - color1.b) * fraction)

  return `rgb(${r}, ${g}, ${b})`
}

// 绘制网格
const drawGrid = () => {
  if (!ctx) return

  const canvas = ctx.canvas
  const { width, height } = heatmapData

  ctx.strokeStyle = 'rgba(191, 203, 217, 0.1)'
  ctx.lineWidth = 1

  // 垂直线
  for (let i = 0; i <= width; i += 10) {
    const x = (i / width) * canvas.width
    ctx.beginPath()
    ctx.moveTo(x, 0)
    ctx.lineTo(x, canvas.height)
    ctx.stroke()
  }

  // 水平线
  for (let i = 0; i <= height; i += 6) {
    const y = (i / height) * canvas.height
    ctx.beginPath()
    ctx.moveTo(0, y)
    ctx.lineTo(canvas.width, y)
    ctx.stroke()
  }
}

// 更新循环
const startUpdateLoop = () => {
  const updateInterval = 1000 / updateRate.value

  const update = (currentTime) => {
    if (currentTime - lastUpdateTime >= updateInterval && isRealtime.value) {
      generatePulseData()
      renderHeatmap()
      lastUpdateTime = currentTime
    }

    animationFrame = requestAnimationFrame(update)
  }

  animationFrame = requestAnimationFrame(update)
}

// 控制函数
const toggleRealtime = () => {
  isRealtime.value = !isRealtime.value
}

const exportData = () => {
  const dataStr = JSON.stringify({
    timestamp: new Date().toISOString(),
    timeWindow: timeWindow.value,
    frequencyRange: frequencyRange.value,
    data: heatmapData.data,
    statistics: {
      currentDensity: currentDensity.value,
      peakDensity: peakDensity.value,
      avgDensity: avgDensity.value,
      totalPulses: totalPulses.value
    }
  }, null, 2)

  const blob = new Blob([dataStr], { type: 'application/json' })
  const url = URL.createObjectURL(blob)

  const link = document.createElement('a')
  link.href = url
  link.download = `pulse_density_${Date.now()}.json`
  link.click()

  URL.revokeObjectURL(url)
  ElMessage.success('数据导出成功')
}

const resetView = () => {
  minThreshold.value = 1.0
  maxThreshold.value = 100
  timeWindow.value = '10s'
  frequencyRange.value = '1-6'
  showDensityValues.value = false
  showGrid.value = true

  initHeatmapData()
  renderHeatmap()

  ElMessage.success('视图已重置')
}

// 参数变化处理
const onTimeWindowChange = () => {
  initHeatmapData()
}

const onFreqRangeChange = () => {
  initHeatmapData()
}

const onThresholdChange = () => {
  renderHeatmap()
}

const onUpdateRateChange = () => {
  if (animationFrame) {
    cancelAnimationFrame(animationFrame)
  }
  startUpdateLoop()
}

// 生命周期
onMounted(() => {
  nextTick(() => {
    initHeatmapData()
    initCanvas()
  })
})

onBeforeUnmount(() => {
  if (animationFrame) {
    cancelAnimationFrame(animationFrame)
  }
})
</script>

<style scoped>
.pulse-density-heatmap {
  width: 100%;
  height: 100%;
  background: #1f2d3d;
  border-radius: 1vh;
  padding: 2vh;
  display: flex;
  flex-direction: column;
  gap: 2vh;
}

/* 控制栏 */
.heatmap-controls {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1.5vh 2vh;
  background: linear-gradient(135deg, #263445, #2d3a4b);
  border-radius: 0.8vh;
  border: 1px solid #3a4a5c;
}

.controls-left {
  display: flex;
  align-items: center;
  gap: 2vw;
}

.heatmap-title {
  margin: 0;
  font-size: 1.2rem;
  font-weight: 600;
  color: #bfcbd9;
  display: flex;
  align-items: center;
  gap: 0.8vw;
}

.density-stats {
  display: flex;
  gap: 0.8vw;
}

/* 热力图容器 */
.heatmap-container {
  flex: 1;
  display: flex;
  gap: 2vh;
  min-height: 50vh;
}

.heatmap-wrapper {
  flex: 1;
  display: grid;
  grid-template-areas:
    "freq-axis canvas"
    "empty time-axis";
  grid-template-columns: 8vh 1fr;
  grid-template-rows: 1fr 4vh;
  gap: 1vh;
}

.frequency-axis {
  grid-area: freq-axis;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.axis-title {
  color: #8591a3;
  font-size: 0.8rem;
  font-weight: 500;
  writing-mode: vertical-rl;
  text-orientation: mixed;
  margin-bottom: 2vh;
}

.frequency-labels {
  flex: 1;
  display: flex;
  flex-direction: column-reverse;
  justify-content: space-between;
  align-items: center;
}

.freq-label {
  color: #bfcbd9;
  font-size: 0.75rem;
  font-family: 'Monaco', 'Consolas', monospace;
}

.heatmap-canvas-container {
  grid-area: canvas;
  position: relative;
  background: #0a0f1b;
  border-radius: 0.5vh;
  border: 1px solid #2d3a4b;
}

.heatmap-canvas {
  width: 100%;
  height: 100%;
  display: block;
}

.density-overlay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  pointer-events: none;
}

.density-cell {
  position: absolute;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #ffffff;
  font-size: 0.6rem;
  font-weight: 500;
  text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.8);
}

.time-axis {
  grid-area: time-axis;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.time-labels {
  flex: 1;
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
}

.time-label {
  color: #bfcbd9;
  font-size: 0.75rem;
  font-family: 'Monaco', 'Consolas', monospace;
}

/* 色彩条 */
.colorbar {
  width: 6vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1vh;
}

.colorbar-title {
  color: #8591a3;
  font-size: 0.8rem;
  font-weight: 500;
  writing-mode: vertical-rl;
  text-orientation: mixed;
}

.colorbar-gradient {
  flex: 1;
  width: 3vh;
  border-radius: 0.3vh;
  border: 1px solid #2d3a4b;
}

.colorbar-scale {
  display: flex;
  flex-direction: column-reverse;
  justify-content: space-between;
  height: 100%;
  align-items: center;
}

.colorbar-tick {
  color: #bfcbd9;
  font-size: 0.65rem;
  font-family: 'Monaco', 'Consolas', monospace;
}

/* 控制面板 */
.control-panels {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 2vh;
}

.control-panel {
  background: #263445;
  border-radius: 0.8vh;
  padding: 1.5vh;
  border: 1px solid #2d3a4b;
}

.panel-title {
  margin: 0 0 1.5vh 0;
  font-size: 1rem;
  font-weight: 600;
  color: #bfcbd9;
}

.control-group {
  display: flex;
  flex-direction: column;
  gap: 1.5vh;
}

.control-item {
  display: flex;
  flex-direction: column;
  gap: 0.8vh;
}

.control-item label {
  color: #8591a3;
  font-size: 0.8rem;
  font-weight: 500;
}

.threshold-controls {
  display: flex;
  flex-direction: column;
  gap: 2vh;
}

.threshold-item {
  display: flex;
  flex-direction: column;
  gap: 1vh;
}

.threshold-item label {
  color: #8591a3;
  font-size: 0.8rem;
  font-weight: 500;
}

.threshold-slider {
  margin-bottom: 0.5vh;
}

.threshold-value {
  color: #409EFF;
  font-size: 0.8rem;
  font-weight: 500;
  text-align: center;
}

.stats-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.5vh;
}

.stat-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.stat-item label {
  color: #8591a3;
  font-size: 0.8rem;
}

.stat-value {
  color: #409EFF;
  font-weight: 500;
  font-size: 0.85rem;
  font-family: 'Monaco', 'Consolas', monospace;
}

/* Element Plus 组件样式覆盖 */
:deep(.el-button) {
  background: #263445 !important;
  border-color: #2d3a4b !important;
  color: #bfcbd9 !important;
}

:deep(.el-button:hover) {
  background: #2d3a4b !important;
  border-color: #409EFF !important;
  color: #409EFF !important;
}

:deep(.el-button--success) {
  background: #67C23A !important;
  border-color: #67C23A !important;
  color: #ffffff !important;
}

:deep(.el-select) {
  width: 100%;
}

:deep(.el-select .el-input__wrapper) {
  background: #263445 !important;
  border-color: #2d3a4b !important;
}

:deep(.el-select .el-input__inner) {
  color: #bfcbd9 !important;
}

:deep(.el-checkbox__label) {
  color: #bfcbd9 !important;
}

:deep(.el-slider__runway) {
  background: #2d3a4b !important;
}

:deep(.el-slider__bar) {
  background: #409EFF !important;
}

:deep(.el-slider__button) {
  background: #409EFF !important;
  border-color: #409EFF !important;
}

:deep(.el-tag) {
  background: #263445 !important;
  border-color: #2d3a4b !important;
  color: #bfcbd9 !important;
}

:deep(.el-tag--success) {
  background: #1f4838 !important;
  color: #67C23A !important;
}

:deep(.el-tag--warning) {
  background: #4a3c1d !important;
  color: #E6A23C !important;
}

/* 响应式设计 */
@media (max-width: 1400px) {
  .control-panels {
    grid-template-columns: 1fr;
    gap: 1.5vh;
  }
}

@media (max-width: 1200px) {
  .heatmap-wrapper {
    grid-template-columns: 6vh 1fr;
  }

  .colorbar {
    width: 5vh;
  }

  .density-stats {
    flex-direction: column;
    gap: 0.5vh;
  }
}

@media (max-width: 768px) {
  .controls-left {
    flex-direction: column;
    align-items: flex-start;
    gap: 1vh;
  }

  .heatmap-container {
    flex-direction: column;
  }

  .colorbar {
    width: 100%;
    height: 6vh;
    flex-direction: row;
  }

  .colorbar-gradient {
    width: 100%;
    height: 3vh;
  }

  .colorbar-scale {
    flex-direction: row;
    width: 100%;
    height: auto;
  }
}
</style>
